﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Text;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Runtime.Hosting;
using System.Workflow.Runtime.Tracking;
using System.Workflow.ComponentModel;
using Openfree.Framework.DataAccess;
using System.Collections.ObjectModel;

namespace Openfree.Workflow.Common
{
	public class WorkflowManager
	{
        private static WorkflowRuntime workflowRuntime = null;
        private static WorkflowService workflowService = null;
        public static string Version = string.Empty;

        public static WorkflowRuntime CurrentWorkflowRuntime
        {
            get
            {
                if (workflowRuntime == null)
                {
                    workflowRuntime = new WorkflowRuntime();
                    Version = DateTime.Now.ToString();
                    //加载通讯服务
                    ExternalDataExchangeService dataService = new ExternalDataExchangeService();
                    workflowRuntime.AddService(dataService);
                    workflowService = new WorkflowService();
                    dataService.AddService(workflowService);

                    //加载持久化服务
                    SqlWorkflowPersistenceService sqlWorkflowPersistenceService =
                        new SqlWorkflowPersistenceService(WorkflowAccess.WFConnection);
                    workflowRuntime.AddService(sqlWorkflowPersistenceService);

                    //相应流程事件
                    workflowRuntime.WorkflowIdled += OnWorkflowIdled;
                    workflowRuntime.WorkflowStarted += OnWorkflowStarted;
                    workflowRuntime.WorkflowTerminated += OnWorkflowTerminated;
                    workflowRuntime.WorkflowCompleted += OnWorkflowCompleted;

                    //加载跟踪服务
                    SqlTrackingService sqlTrackingService = new SqlTrackingService(WorkflowAccess.WFConnection);
                    sqlTrackingService.IsTransactional = false;
                    workflowRuntime.AddService(sqlTrackingService);

                    workflowRuntime.StartRuntime();
                    //加载持久化的工作流
                    foreach (SqlPersistenceWorkflowInstanceDescription desc in workflowRuntime.GetService<SqlWorkflowPersistenceService>().GetAllWorkflows())
                    {
                        try
                        {
                            workflowRuntime.GetWorkflow(desc.WorkflowInstanceId);
                        }
                        catch
                        {
                            
                        }
                    }
                }

                return workflowRuntime;
            }
        }

        private static void OnWorkflowIdled(object sender, WorkflowEventArgs e)
        {
            e.WorkflowInstance.TryUnload();
        }

        private static void OnWorkflowStarted(object sender, WorkflowEventArgs e)
        {
            WorkflowAccess.SetWorkflowState(e.WorkflowInstance.InstanceId, WorkflowStatus.Running);
        }

        private static void OnWorkflowTerminated(object sender, WorkflowEventArgs e)
        {
            WorkflowAccess.SetWorkflowState(e.WorkflowInstance.InstanceId, WorkflowStatus.Terminated);
        }

        private static void OnWorkflowCompleted(object sender, WorkflowEventArgs e)
        {
            WorkflowAccess.SetWorkflowState(e.WorkflowInstance.InstanceId, WorkflowStatus.Completed);
        }

        public static string AddWorkflow(Type workflowType, bool isSubmit, object startParameter)
        {
            Dictionary<string, object> inputParameters = new Dictionary<string, object>();
            inputParameters.Add("InputParameters", startParameter);
            WorkflowInstance workflowInstance = CurrentWorkflowRuntime.CreateWorkflow(workflowType, inputParameters);            
            workflowInstance.Start();            
            if (isSubmit)
            {
                RaiseApproveEvent(workflowInstance.InstanceId, null);
            }
            return workflowInstance.InstanceId.ToString();
        }

        public static void StartWorkflow(Guid instanceID)
        {
            WorkflowInstance workflowInstance = CurrentWorkflowRuntime.GetWorkflow(instanceID); 
            workflowInstance.Start();
        }

        public static void TerminateWolkflow(Guid instanceID)
        {
            WorkflowInstance workflowInstance = CurrentWorkflowRuntime.GetWorkflow(instanceID);
            workflowInstance.Terminate("Terminate:" + instanceID.ToString());
        }

        public static void RaiseApproveEvent(Guid instanceID, Object externalData)
        {
            WorkflowService workflowService = (WorkflowService)CurrentWorkflowRuntime.GetService(typeof(WorkflowService));
            workflowService.RaiseApproveEvent(instanceID, externalData);
        }

        public static void RaiseRejectEvent(Guid instanceID, Object externalData)
        {
            WorkflowService workflowService = (WorkflowService)CurrentWorkflowRuntime.GetService(typeof(WorkflowService));
            workflowService.RaiseRejectEvent(instanceID, externalData);
        }

        public static void RaiseSendBackEvent(Guid instanceID, Object externalData)
        {
            WorkflowService workflowService = (WorkflowService)CurrentWorkflowRuntime.GetService(typeof(WorkflowService));
            workflowService.RaiseSendBackEvent(instanceID, externalData);
        }

        public static void RaiseUpdateEvent(Guid instanceID, Object externalData)
        {
            WorkflowService workflowService = (WorkflowService)CurrentWorkflowRuntime.GetService(typeof(WorkflowService));
            workflowService.RaiseUpdateEvent(instanceID, externalData);
        }

        /// <summary>
        /// 获取我申请正在办理的流程
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public static DataSet LoadOwnerWorkflow(string userID)
        {
            List<string> ruleList = new List<string>();
            string cmdText = @"select a.*, '{0}' CurrentActivity,
                    (select Username from T_User where UserID=a.UserID) Username,
                    (select top 1 CodeName from T_CodeConfig where GroupCode=b.GroupCode and Category='WorkflowGroup') GroupCodeName,
                    b.Subject CategorySubject,
                    b.CategoryID
                    from T_Workflow a left join T_WorkflowCategory b 
                    on a.CategoryCode=b.CategoryCode where CurrentState<>'Completed' and a.UserID='{1}' order by a.CreateDate desc ";
            DataSet dsWorkflow = BaseAccess.GetDataSet(WorkflowAccess.SYSConnection, string.Format(cmdText, "", userID));
            return dsWorkflow;
        }


        /// <summary>
        /// 获取等待我办理的流程
        /// </summary>
        /// <param name="userID"></param>
        /// <returns></returns>
        public static DataSet LoadWaitingWorkflow(string userID, string orgTreeCategory, string orgTreeQueryCode)
        {
            List<string> ruleList = new List<string>();
//            string cmdText = @"select m.*,n.QueryCode from (
//                                select a.*,
//                                (select Username from T_User where UserID=a.UserID) Username,
//                                (select top 1 CodeName from T_CodeConfig where GroupCode=b.GroupCode and Category='WorkflowGroup') GroupCodeName,
//                                b.Subject CategorySubject
//                                from T_Workflow a left join T_WorkflowCategory b 
//                                on a.CategoryCode=b.CategoryCode where a.IsSubmit=1 
//                            ) m left join (
//                                select QueryCode, UserID from T_OrgTree a left join T_OrgUser b
//                                on a.OrgID=B.OrgID  where  a.Category='{0}' 
//                            )
//                            n on m.UserID=n.UserID where and n.QueryCode like '{1}%'
//                            order by m.CreateDate desc";
//            DataSet dsWorkflow = BaseAccess.GetDataSet(WorkflowAccess.SYSConnection, string.Format(cmdText, orgTreeCategory, orgTreeQueryCode));

            
            string cmdText = @"select m.*, n.IsProcess from (
                                select a.*,
                                (select Username from T_User where UserID=a.UserID) Username,
                                (select top 1 CodeName from T_CodeConfig where GroupCode=b.GroupCode and Category='WorkflowGroup') GroupCodeName,
                                b.Subject CategorySubject,
                                b.CategoryID
                                from T_Workflow a left join T_WorkflowCategory b 
                                on a.CategoryCode=b.CategoryCode where a.CurrentState<>'Completed' and a.IsSubmit=1 
                            ) m left join T_WorkflowProcess
                            n on m.InstanceID=n.InstanceID where n.UserID='{0}' and n.IsProcess=0 
                            order by m.CreateDate desc";
            DataSet dsWorkflow = BaseAccess.GetDataSet(WorkflowAccess.SYSConnection, string.Format(cmdText, userID));
          
            using (SqlConnection conn = new SqlConnection(WorkflowAccess.SYSConnection))
            {
                SecurityAccess securityAccess = new SecurityAccess(conn);
                DataSet ds = securityAccess.GetUserRule(userID, "Workflow");
                foreach (DataRow row in ds.Tables[0].Rows)
                {
                    ruleList.Add(row["ContainerName"].ToString());
                }
            }

            //加载持久化的工作流
            foreach (SqlPersistenceWorkflowInstanceDescription desc in CurrentWorkflowRuntime.GetService<SqlWorkflowPersistenceService>().GetAllWorkflows())
            {
                try
                {
                    //WorkflowInstance workflowInstance = WorkflowMgr.CurrentWorkflowRuntime.GetWorkflow(desc.WorkflowInstanceId);
                    StateMachineWorkflowInstance smwi = new StateMachineWorkflowInstance(CurrentWorkflowRuntime, desc.WorkflowInstanceId);
                    if (ruleList.Contains(smwi.CurrentStateName))
                    {
                        //DataSet ds = BaseAccess.GetDataSet(WorkflowAccess.SYSConnection,
                        //    string.Format(cmdText, smwi.CurrentStateName, smwi.InstanceId));

                        DataSet ds = BaseAccess.GetDataSet(WorkflowAccess.SYSConnection,
                            string.Format(cmdText, orgTreeCategory, smwi.InstanceId, orgTreeQueryCode));
                        if (ds.Tables[0].Rows.Count > 0)
                        {
                            //如果提交用户组织机构是当前用户组织机构的同下级节点则加载
                            dsWorkflow.Tables[0].Rows.Add(ds.Tables[0].Rows[0].ItemArray);
                        }
                    }
                }
                catch { }
            }
            return dsWorkflow;
        }


        public static DataSet LoadWorkflowDefinition(Type workflowType)
        {
            WorkflowRuntime runtime = new WorkflowRuntime();
            WorkflowInstance instance = runtime.CreateWorkflow(workflowType);
            Activity activity = instance.GetWorkflowDefinition();

            DataSet dataSet = new DataSet();
            DataTable table = new DataTable("TableName");
            DataColumn column;
            DataColumnCollection columns = table.Columns;
            column = columns.Add("QualifiedName", typeof(System.String));
            column.DefaultValue = string.Empty;
            column = columns.Add("ParentQualifiedName", typeof(System.String));
            column.DefaultValue = string.Empty;
            column = columns.Add("Description", typeof(System.String));
            column.DefaultValue = string.Empty;
            column = columns.Add("Type", typeof(System.String));
            column.DefaultValue = string.Empty;
            column = columns.Add("OrderIndex", typeof(System.Int32));
            column.DefaultValue = 0;
            dataSet.Tables.Add(table);

            int index = 0;
            FillWorkflowDefinition(activity, string.Empty, dataSet, ref index);
            return dataSet;
        }

        private static void FillWorkflowDefinition(object activity, string parentQualifiedName, DataSet dataSet, ref int index)
        {
            if (activity is CompositeActivity)
            {
                CompositeActivity comActivity = activity as CompositeActivity;
                foreach (object obj in comActivity.Activities)
                {
                    DataRow row = dataSet.Tables[0].NewRow();
                    row["QualifiedName"] = (obj as Activity).QualifiedName;
                    row["ParentQualifiedName"] = parentQualifiedName;
                    row["Description"] = (obj as Activity).Description;
                    row["Type"] = (obj as Activity).GetType().ToString();
                    row["OrderIndex"] = index;
                    dataSet.Tables[0].Rows.Add(row);
                    index++;
                    FillWorkflowDefinition(obj, (obj as Activity).QualifiedName, dataSet, ref index);//递归
                }
            }
            else
            {
                if (activity is Activity)
                {
                    Activity cat = activity as Activity;
                    DataRow row = dataSet.Tables[0].NewRow();
                    row["QualifiedName"] = cat.QualifiedName;
                    row["ParentQualifiedName"] = parentQualifiedName;
                    row["Description"] = cat.Description;
                    row["Type"] = cat.GetType().ToString();
                    row["OrderIndex"] = index;
                    dataSet.Tables[0].Rows.Add(row);
                    index++;
                }
            }
        }

        public static string GetActivityDescription(Type workflowType)
        {
            WorkflowRuntime runtime = new WorkflowRuntime();
            WorkflowInstance instance = runtime.CreateWorkflow(workflowType);
            Activity activity = instance.GetWorkflowDefinition();
            
            string result = activity.Description;
            runtime.Dispose();
            return result;
        }

        public static string GetActivityState(Guid instanceID)
        {
            StateMachineWorkflowInstance smwi = new StateMachineWorkflowInstance(CurrentWorkflowRuntime, instanceID);
            return smwi.CurrentStateName;
        }


        public static ReadOnlyCollection<string> GetEventAllowed(Guid instanceID)
        {
            List<string> events = new List<string>();
            StateMachineWorkflowInstance smwi = new StateMachineWorkflowInstance(CurrentWorkflowRuntime, instanceID);

            foreach (Activity a in smwi.CurrentState.EnabledActivities)
            {
                if (a is EventDrivenActivity)
                {
                    FindEventAllowed((CompositeActivity)a, events);
                }
            }

            // Get set event from the event drivens in the super states
            CompositeActivity curactivity = smwi.CurrentState.Parent;
            while (curactivity != null)
            {
                foreach (Activity b in curactivity.EnabledActivities)
                {
                    if (b is EventDrivenActivity)
                    {
                        FindEventAllowed((CompositeActivity)b, events);
                    }
                }
                curactivity = curactivity.Parent;
            }
            return events.AsReadOnly();
        }


        private static void FindEventAllowed(CompositeActivity parent, List<string> events)
        {
            foreach (Activity activity in parent.EnabledActivities)
            {
                if (activity is HandleExternalEventActivity)
                {
                    string message = ((HandleExternalEventActivity)activity).EventName;
                    if (message != null)
                        events.Add(message);
                }
                else
                {
                    if (activity is CompositeActivity)
                    {
                        FindEventAllowed((CompositeActivity)activity, events);
                    }
                }
            }
        }
	}
}
